﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HystereticBasic
{
    /// <summary>
    /// 加载卸载序列集合
    /// </summary>
    public class LoadingPathSet
    {
        /// <summary>
        /// 所有加载-卸载序列
        /// </summary>
        private List<LoadingPath> TotalLoadPathList { set; get; }

        /// <summary>
        /// 目标加载-卸载序列
        /// </summary>
        private List<LoadingPath> TargetLoadPathList { set; get; }

        /// <summary>
        /// 数据点过滤后的滞回曲线
        /// </summary>
        private ForceDispObj filterOriginForceDispObj { set; get; }

        /// <summary>
        /// 加载卸载路径数目
        /// </summary>
        public int Count
        {
            get
            {
                return this.TargetLoadPathList.Count;
            }
        }

        /// <summary>
        /// 获得加载-卸载路径
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public LoadingPath this[int index]
        {
            get
            {
                if (index >= this.Count) return new LoadingPath();
                return this.TargetLoadPathList[index];
            }
        }

        /// <summary>
        /// 内力最大点
        /// </summary>
        public ForceDispBasicPair ForceMaxPoint
        {
            get
            {
                //获得内力最大点
                var forceMaxPt = this.filterOriginForceDispObj.ForceMaxPoint;
                //内力点存在
                return forceMaxPt.Force > 0? forceMaxPt: new ForceDispBasicPair();
            }
        }

        /// <summary>
        /// 内力最小点
        /// </summary>
        public ForceDispBasicPair ForceMinPoint
        {
            get
            {
                //获得内力最小点
                var forceMinPt = this.filterOriginForceDispObj.ForceMinPoint;
                //内力点存在
                return forceMinPt.Force < 0 ? forceMinPt : new ForceDispBasicPair();
            }
        }

        /// <summary>
        /// 内力最大值限定
        /// </summary>
        private ForceDispBasicPair forceMaxLimitPoint
        {
            get
            {
                //获得力最大点
                var maxPt = this.ForceMaxPoint;
                var minPt = this.ForceMinPoint;
                //有一者不存在
                if (Math.Abs(maxPt.Force) < GlobalParam.ForceTol
                  || Math.Abs(minPt.Force) < GlobalParam.ForceTol)
                    return maxPt;
                //力限定值
                var limitForce = Math.Max(Math.Abs(maxPt.Force),
                    Math.Abs(minPt.Force)) * GlobalParam.MaxForceLimitRatio;
                //是否大于限定值
                if (Math.Abs(maxPt.Force) > limitForce) return maxPt;
                else return new ForceDispBasicPair(maxPt.Disp, (float)limitForce);
            }
        }

        /// <summary>
        /// 内力最大值限定
        /// </summary>
        private ForceDispBasicPair forceMinLimitPoint
        {
            get
            {
                //获得力最大点
                var maxPt = this.ForceMaxPoint;
                var minPt = this.ForceMinPoint;
                //有一者不存在
                if (Math.Abs(maxPt.Force) < GlobalParam.ForceTol
                  || Math.Abs(minPt.Force) < GlobalParam.ForceTol)
                    return minPt;
                //力限定值
                var limitForce = Math.Max(Math.Abs(maxPt.Force),
                    Math.Abs(minPt.Force)) * GlobalParam.MaxForceLimitRatio;
                //是否大于限定值
                if (Math.Abs(minPt.Force) > limitForce) return minPt;
                else return new ForceDispBasicPair(minPt.Disp, -(float)limitForce);
            }
        }

        /// <summary>
        /// 数据点过滤
        /// </summary>
        /// <param name="originForceDispObj"></param>
        private int FilterOriginObj(ForceDispObj originForceDispObj)
        {
            //初始化起点
            var prePt = new ForceDispBasicPair();
            //初始化
            this.filterOriginForceDispObj.Add(prePt);
            //遍历数据
            foreach (var obj in originForceDispObj.ToList())
            {
                //满足位移容差 
                if (Math.Abs(obj.Disp - prePt.Disp) < GlobalParam.DispTol)
                    continue;
                //满足位移容差 
                if (Math.Abs(obj.Force) < GlobalParam.ForceTol)
                    continue;
                //出现负刚度
                if (prePt.GetStiffness(obj) < 0)
                {
                    //1-2象限:位移减小
                    if (obj.Force > 0 && obj.Disp - prePt.Disp < 0)
                        continue;
                    //3-4象限:位移增大
                    else if (obj.Force < 0 && obj.Disp - prePt.Disp > 0)
                        continue;
                }
                //都满足
                this.filterOriginForceDispObj.Add(obj);
                prePt = obj;
            }
            //返回过滤点数目
            return originForceDispObj.Count - this.filterOriginForceDispObj.Count;
        }

        /// <summary>
        /// 初始化加载-卸载路径
        /// </summary>
        private void initialLoadPathList()
        {
            //最大力点
            var forceMaxPt = this.ForceMaxPoint;
            var forceMinPt = this.ForceMinPoint;
            //初始化
            var index = 0;
            //计算割线刚度
            var posSecantStiff = forceMaxPt.Force > 0 ? forceMaxPt.SecantStiffness : 0;
            var negSecantStiff = forceMinPt.Force < 0 ? forceMinPt.SecantStiffness : 0;
            //是否存在加载对象
            bool isPosLoadingExist = false;
            bool isNegLoadingExist = false;
            //遍历数据构造
            for (; index < this.filterOriginForceDispObj.Count - 1;)
            {
                //构造加载卸载路径
                var loadPath = new LoadingPath(this.filterOriginForceDispObj, ref index);
                //不存在数据点
                if (!loadPath.isLegal) continue;
                //判断加载方向
                if ((loadPath.isPosLoading && !isPosLoadingExist) || (!loadPath.isPosLoading && !isNegLoadingExist))
                {
                    //获得割线刚度
                    var targetSecantStiff = (loadPath.isPosLoading ? posSecantStiff : negSecantStiff) * GlobalParam.iniPathSectStiffRatio;
                    //割线刚度小于等于0
                    if (targetSecantStiff <= 0) continue;
                    //获得峰值变形
                    var dispMax = loadPath.isPosLoading ? forceMaxPt.Disp : forceMinPt.Disp;
                    //峰值指向点
                    var peakPt = loadPath.PeakOreintedPt;
                    //小于峰值变形 且 割线刚度小
                    if (Math.Abs(peakPt.Disp) < Math.Abs(dispMax) && peakPt.SecantStiffness < targetSecantStiff)
                        continue;
                    else if (loadPath.isPosLoading) isPosLoadingExist = true;
                    else isNegLoadingExist = true;
                }
                //添加对象
                this.TotalLoadPathList.Add(loadPath);
            }
        }

        /// <summary>
        /// 合并加载卸载路径
        /// </summary>
        /// <returns></returns>
        private int combineLoadPathList()
        {
            //获得力最大点和力最小点
            var posForceLimit = this.forceMaxLimitPoint.Force * GlobalParam.LoadPathCapacityRatio;
            var negForceLimit = this.forceMinLimitPoint.Force * GlobalParam.LoadPathCapacityRatio;
            //遍历所有数据
            for (int tIndex = 0; tIndex < this.TotalLoadPathList.Count; tIndex++)
            {
                //获得对象
                var loadPath = this.TotalLoadPathList[tIndex];
                //承载力限值
                var capacityLimit = loadPath.isPosLoading ? posForceLimit : negForceLimit;
                //对象处理方法
                var actionEnum = loadPath.GetLoadPathAction(capacityLimit);
                //跳过
                if (actionEnum == LoadPathAction.Remove) continue;
                //添加
                else if (actionEnum == LoadPathAction.AddObj) this.TargetLoadPathList.Add(loadPath);
                //存在下一滞回环
                else if (tIndex + 1 < this.TotalLoadPathList.Count)
                {
                    //对象处理方法
                    actionEnum = this.TotalLoadPathList[tIndex + 1].AddPreLoadPath(loadPath, capacityLimit);
                    //添加对象
                    if(actionEnum == LoadPathAction.AddObj)
                        this.TargetLoadPathList.Add(loadPath);
                }
                //不存在下一滞回环
                else this.TargetLoadPathList.Add(loadPath);
            }
            return this.TotalLoadPathList.Count - this.TargetLoadPathList.Count;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public LoadingPathSet()
        {
            this.TotalLoadPathList = new List<LoadingPath>();
            this.TargetLoadPathList = new List<LoadingPath>();
            this.filterOriginForceDispObj = new ForceDispObj();
        }

        /// <summary>
        /// 构造加载卸载路径
        /// </summary>
        /// <param name="originForceDispObj"></param>
        public LoadingPathSet(ForceDispObj originForceDispObj) : this()
        {
            //过滤数据点
            int filterCount = this.FilterOriginObj(originForceDispObj);
            //初始化加载-卸载路径
            this.initialLoadPathList();
            //合并加载-卸载路径
            int combineCount = this.combineLoadPathList();
        }

    }
}
